﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Service.Domain.Conventions
{
    public class ConventionGroup<T> : BaseConvention<T>, IConvention<T> where T : class
    {
        protected IConvention<T> Left { get; set; }
        protected IConvention<T> Right { get; set; }
        protected ConventionType Type { get; set; }

        public ConventionGroup(ConventionType type, IConvention<T> left, IConvention<T> right)
        {
            this.Type = type;
            this.Left = left;
            this.Right = right;
        }

        public override Expression<Func<T, bool>> ToExpression()
        {
            if (this.Left == null && this.Right == null) return null;

            if (this.Left == null && this.Right != null) return this.Right.ToExpression();
            if (this.Right == null && this.Left != null) return this.Left.ToExpression();

            BinaryExpression binary = null;
            var left = this.Left.ToExpression();
            var right = this.Right.ToExpression();
            switch (this.Type)
            {
                case ConventionType.AND:
                    binary = Expression.And(left, right);
                    break;
                case ConventionType.OR:
                    binary = Expression.Or(left, right);
                    break;
            }
            return Expression.Lambda<Func<T, bool>>(binary, right.Parameters);
        }

        public override string ToSql()
        {
            if (this.Left == null && this.Right == null) return null;

            if (this.Left == null && this.Right != null) return this.Right.ToSql();
            if (this.Right == null && this.Left != null) return this.Left.ToSql();

            return string.Format(@$"({this.Left.ToSql()}) {this.Type} ({this.Right.ToSql()})");
        }

        public override Func<T, bool> ToAction()
        {
            return this.ToExpression().Compile();
        }
    }
}
